/**
 * 
 */
package com.massyframework.beanskin.graphql.context;

import java.util.List;
import java.util.Objects;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.graphql.GraphQLTypeName;
import com.massyframework.beanskin.service.ServiceRepository;
import com.massyframework.beanskin.service.metadata.ClassMetadata;
import com.massyframework.beanskin.service.metadata.MetadataRepository;

import graphql.TypeResolutionEnvironment;
import graphql.schema.GraphQLObjectType;
import graphql.schema.TypeResolver;


/**
 * {@link ModuleTypeResolver},支持装配件的类型解析器
 * @author huangkaihui
 *
 */
public class ModuleTypeResolver implements TypeResolver {

	private final Module<?> module;
	private MetadataRepository metadataRepository;
	private String defaultTypeName;
	
	/**
	 * 构造方法
	 */
	public ModuleTypeResolver(Module<?> module, String defaultTypeName) {
		this.module =
			Objects.requireNonNull(module, "\"module\" cannot be null.");
		this.defaultTypeName = Objects.requireNonNull(defaultTypeName, "\"defaultTypeName\" cannot be null.");
	}
	
	/* (non-Javadoc)
	 * @see graphql.schema.TypeResolver#getType(graphql.TypeResolutionEnvironment)
	 */
	@Override
	public GraphQLObjectType getType(TypeResolutionEnvironment env) {
		Object source = env.getObject();
		Class<?> clazz = source.getClass();
		
		String name = this.retrieveTypeName(clazz);
		return (GraphQLObjectType) env.getSchema().getType(name);
	}
	
	/**
	 * 取回GraphQL的类名
	 * @param clazz {@link Class}
	 * @return {@link String}
	 */
	protected String retrieveTypeName(Class<?> clazz) {
		GraphQLTypeName typeName = this.scanAnnotation(clazz);
		return typeName != null ?
				typeName.value():
					this.getDefaultTypeName();
	}

	/**
	 * 扫描GraphQLTypeName注解
	 * @param clazz {@link Class}
	 * @return {@link GraphQLTypeName}
	 */
	protected GraphQLTypeName scanAnnotation(Class<?> clazz) {
		MetadataRepository repo = this.getMetadataRepository();
		List<ClassMetadata> metadatas = repo.getHierarchyClassMetadatas(clazz);
		for (ClassMetadata metadata: metadatas) {
			GraphQLTypeName anno =
					metadata.findAnnotation(GraphQLTypeName.class);
			if (anno != null) {
				return anno;
			}
		}
		
		return null;
	}

	/**
	 * 模块
	 * @return {@link Module}
	 */
	public Module<?> getModule() {
		return this.module;
	}
	
	/**
	 * 元数据仓储
	 * @return {@link MetadataRepository}
	 */
	public MetadataRepository getMetadataRepository() {
		if (this.metadataRepository == null) {
			ServiceRepository repo = ServiceRepository.retrieveFrom(this.getModule());
			this.metadataRepository = repo.getService(MetadataRepository.class);
			
		}
		return this.metadataRepository;
	}

	protected String getDefaultTypeName() {
		return this.defaultTypeName;
	}
}
